package com.xcm.filter;

import com.alibaba.fastjson.JSONObject;
import com.xcm.cache.RedisCacheDao;
import com.xcm.constant.BaseConstant;
import com.xcm.sso.SSOProperties;
import com.xcm.constant.CacheConstant;
import com.xcm.constant.CookieConstant;
import com.xcm.sso.SSOContants;
import com.xcm.model.SysUser;
import com.xcm.model.response.MyHttpStatus;
import com.xcm.sso.DESUtils;
import com.xcm.sso.SSOUtils;
import com.xcm.util.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 单点登录过滤器
 *
 * @author 林强
 * @date 2018-04-12 11:15
 */
public class SSOLoginFilter implements Filter {
    public static Logger logger = LoggerFactory.getLogger(SSOLoginFilter.class);

    @Autowired
    private RedisCacheDao redisCacheDao;
    @Autowired
    private SSOProperties ssoProperties;

    @Override
    public void init(FilterConfig filterConfig) {
        ServletContext servletContext = filterConfig.getServletContext();
        ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        redisCacheDao = (RedisCacheDao) ctx.getBean("redisCacheDao");
        ssoProperties = (SSOProperties) ctx.getBean("ssoProperties");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
                         FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        String redirectURL = request.getRequestURL().toString();
        boolean isExcludeUrl = isPass(request);
        if (isExcludeUrl) {
            //不需要拦截的方法，静态资源等直接放过
            chain.doFilter(req, res);
            return;
        }
        //是否是ajax请求
        boolean isAjax = isAjax(request);
        //通过ticket验证是否登录
        String ticket = CookieUtils.getCookieValueByName(request, CookieConstant.WHOLE_COOKIE_NAME);
        if (null == ticket || StringUtils.isBlank(ticket)) {
            if (isAjax) {
                writeNeedLoginResultForAjax(request, response);
                return;
            }
            String ssoLoginUrl = SSOUtils.createPortalLoginUrl(ssoProperties, redirectURL);
            response.sendRedirect(ssoLoginUrl);
            return;
        }
        SysUser sessionUser = SessionUtils.getSessionUser(request);
        if (null != sessionUser) {
            chain.doFilter(req, res);
            return;
        }
        ticket = DESUtils.decrypt(ticket, ssoProperties.getSecretKey());
        boolean idLogin = redisCacheDao.hasKey(ssoProperties.getSsoTicketsCacheName(), ticket);
        if (idLogin) {
            chain.doFilter(req, res);
            return;
        }
        if (isAjax) {
            writeNeedLoginResultForAjax(request, response);
            return;
        }
        // 未登录，跳转到SSO登录
        String ssoLoginUrl = SSOUtils.createPortalLoginUrl(ssoProperties, redirectURL);
        response.sendRedirect(ssoLoginUrl);
        return;
    }

    @Override
    public void destroy() {
    }

    /**
     * 判断是否是ajax请求
     *
     * @param request
     * @return
     */
    private static boolean isAjax(HttpServletRequest request) {
        boolean isAjax = false;
        if (request.getHeader("x-requested-with") != null && "XMLHttpRequest".equals(request.getHeader("x-requested-with"))) {
            isAjax = true;
        }
        return isAjax;
    }

    /**
     * 未登录时对ajax请求的处理
     *
     * @param response
     */
    private void writeNeedLoginResultForAjax(HttpServletRequest request, HttpServletResponse response) {
        try {
            response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
            response.addHeader("Access-Control-Allow-Credentials", "true");
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json; charset=utf-8");
            PrintWriter out = response.getWriter();
            JSONObject result = new JSONObject();
            result.put(BaseConstant.CODE, MyHttpStatus.FORBIDDEN.code());
            result.put(BaseConstant.MSG, MyHttpStatus.FORBIDDEN.getReasonPhrase());
            result.put(SSOContants.PLATFORM_TAG, ssoProperties.getSystemSignPortal());
            result.put(SSOContants.SET_COOKIE_URL, DESUtils.encrypt(SSOContants.PATH.PORTAL_METHOD_SETCOOKIE.getValue(), ssoProperties.getSecretKey()));
            //默认登录成功跳转的请求
            result.put(SSOContants.REDIRECT_URL, DESUtils.encrypt(SSOContants.PATH.PORTAL_METHOD_INDEX.getValue(), ssoProperties.getSecretKey()));
            out.write(result.toJSONString());
            out.flush();
            out.close();
        } catch (IOException e) {
            logger.error("SSOLoginFilter writeNeedLoginResult 单点拦截到ajax未登录时处理出现异常：" + e.getMessage());
        }
    }

    /**
     * 单点过滤器是否需要放行
     *
     * @param request
     * @return true放行，反之拦截
     */
    private boolean isPass(HttpServletRequest request) {
        String urL = request.getRequestURL().toString();
        String uri = request.getRequestURI();
        try {
            if (ssoProperties.getExcludeUrls().contains(uri)) {
                return true;
            }
            for (int i = 0, j = ssoProperties.getStaticResourceSufixs().size(); i < j; i++) {
                if (urL.contains(ssoProperties.getStaticResourceSufixs().get(i))) {
                    return true;
                }
            }
        } catch (Exception e) {
            logger.error("SSOLoginFilter isPass 单点验证是否需要拦截url异常：" + e.getMessage());
        }
        return false;
    }
}
